home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d20 / pxsrc21a.arc / PAKSORTM.C < prev    next >
Text File  |  1991-05-12  |  14KB  |  554 lines

  1. /*
  2.         PAKSORTM.C         Sort contents of .ARC archive.
  3.         Copyright 1989 by Jeffrey J. Nonken
  4.         Released to public domain.
  5.  
  6.         Modified from PAKSORT.C: Copyright 1988, Michael J. Housky
  7.         Released to the Public Domain ... *no* rights reserved.
  8.  
  9.         I ripped off Mike's code from the stand-alone program PAKSORT in
  10.         order to include it into PolyXarc as a module. The only changes I
  11.         made were: stripped the main() function out, removed the order[]
  12.         variable and hard-coded the sort order, and added code to record
  13.         the highest compression type value (so I can tell whether to use
  14.         ARCE, PKUNPAK, or PAK) to discombobulate. I also now allocate the
  15.         buffer, rather than having a fixed buffer size.
  16. */
  17.  
  18. /*
  19.     Update log:
  20.  
  21.     12 May 1991: Separated header errors from open/read errors; header
  22.         errors now return 6 instead of 1 so we know that we can rename
  23.         them and go on if we're doing bundles.
  24.     18 September 1990: added support for type 1 headers (which are 4 bytes
  25.         shorter than all other header types); added support for version 6
  26.         archives. Version 6 archives have some advanced stuff that version
  27.         5 archives don't have, and some of it is position dependent, so we
  28.         WON'T sort version 6 archives. Since PKPAK never got past version 5
  29.         headers, that's not a problem. Type 1 headers are considered obsolete,
  30.         but I wouldn't want this to bomb for such a stupid reason. Removed
  31.         .olen from the local header stuff; it's not used for anything once
  32.         we've tested the header for validity. jjn
  33.     22 March 1990: added Amiga stuff. jjn & smp
  34.     14 November 1989: modified from PAKSORT.C. jjn
  35.  
  36. PAKSORT.C update log:
  37.     Version 1.1, 24 January 1989: changed default extension .PAK to .ARC. jjn
  38.     Version 1.0, 25 August 1988: First version.
  39. */
  40.  
  41. #include <string.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44.  
  45. #ifndef AMIGA
  46. #    include <io.h>
  47. #endif
  48.  
  49. #ifdef AMIGA
  50. #define _NEAR_
  51. #endif
  52.  
  53. #ifdef TURBOC
  54. #define _NEAR_
  55. #endif
  56.  
  57. #ifdef MSC
  58. #include <malloc.h>
  59. #define _NEAR_ near
  60. #endif
  61.  
  62.  
  63. #include "p_common.h"
  64. #include "pakmdefn.h"
  65.  
  66. #define MAX_BUFSIZE     32760
  67.  
  68. typedef struct                    /* stored directory format: */
  69. {
  70.     int32        floc;            /* byte location of header in file */
  71.     int32        slen;            /* stored (packed) length of file */
  72. /*     int32        olen;             * original (unpacked) length of file */
  73.     word16        ddate;            /* DOS date of update */
  74.     word16        dtime;            /* DOS time of update */
  75.     char        fname[13];        /* filename */
  76.     unsigned char type;            /* Header type. */
  77. } pak_dir;
  78.  
  79. /* ------------ Global data: */
  80.  
  81.  
  82. byte            * _NEAR_ pak_buf;        /* buffer for reading pakfile data */
  83. pak_hdr         _NEAR_ fhdr;            /* buffer for reading pakfile header */
  84. long            _NEAR_ pakloc;            /* location in input file */
  85. long            _NEAR_ pakloc,
  86.                 _NEAR_ paklen;            /* length of input file */
  87. int             _NEAR_ memory;
  88. int16            _NEAR_ highest_type;
  89. int16            _NEAR_ version6;        /* True if version 6 header. */
  90.  
  91. extern int        _NEAR_ quiet;
  92.  
  93.  
  94.  
  95. /*****************************************************************************
  96. This will turn an Intel-format integer into a Motorola-format integer.
  97. *****************************************************************************/
  98. #ifdef MOTOROLA
  99. void swap_Intel(char *address, int numbytes)
  100. {
  101. register int i; /* Ascending index. */
  102. register int j; /* Descending index. */
  103. char    c;        /* Temporary storage for the swap. */
  104.  
  105.     for (i = 0, j = numbytes - 1; i < j; ++i, --j)
  106.     {
  107.         c = address[i];
  108.         address[i] = address[j];
  109.         address[j] = c;
  110.     }
  111. }
  112. #endif
  113.  
  114. /*
  115.         read_pakhdr:    Read header of .ARC member file
  116.  
  117. Reads next header sequentially from file.
  118.  
  119. Returns 0 if good header, and global fhdr has header.
  120. Returns +1 if end of file marker found.
  121. Returns -1 if bad header or read error.
  122.  
  123. */
  124.  
  125. int read_pakhdr(FILE *fp)
  126. {
  127.     register int i;
  128.  
  129.     i = fgetc(fp);                        /* get file marker */
  130.     if ( i != PAK_MARK )                /* error if not correct */
  131.         return -1;
  132.  
  133.     i = fread( (char*)&fhdr, 1, PAK_HDRLEN, fp );
  134.                                         /* read header, follows mark */
  135. #ifdef MOTOROLA
  136.     swap_Intel((char *)&fhdr.slen ,sizeof(fhdr.slen) );
  137.     swap_Intel((char *)&fhdr.ddate,sizeof(fhdr.ddate));
  138.     swap_Intel((char *)&fhdr.dtime,sizeof(fhdr.dtime));
  139.     swap_Intel((char *)&fhdr.crc  ,sizeof(fhdr.crc)  );
  140.     swap_Intel((char *)&fhdr.olen ,sizeof(fhdr.olen) );
  141. #endif
  142.  
  143.     if ( i>=1 && fhdr.type==0 )         /* type 0 header is an EOF mark */
  144.         return 1;                        /* end of file mark seen */
  145.  
  146.     if (fhdr.type == 1)                    /* Header type 1 is 4 bytes short. */
  147.     {
  148.         fhdr.olen = fhdr.slen;            /* Use the stored length. */
  149.         fseek(fp,-4l,1);                /* Seek relative backwards by 4. */
  150.     }
  151.     
  152.     if ( i!=PAK_HDRLEN || fhdr.slen<0L)
  153.         return -1;                        /* invalid header seen */
  154.  
  155.     if (fhdr.type < 20 && fhdr.olen < fhdr.slen)
  156.         return -1;                        /* invalid header seen */
  157.  
  158.     pakloc = ftell(fp);                 /* note start of data and test */
  159.     if ( pakloc+fhdr.slen > paklen )    /*    for all data present */
  160.         return -1;                        /* no: presume truncated file */
  161.     return 0;
  162.  
  163. } /* read_pakhdr */
  164.  
  165.  
  166. /*
  167.         pak_getdir:     Build directory of .ARC file headers.
  168.  
  169. Sequentially read and validate all headers within pakfile. Build malloc-ed
  170. table of headers found.
  171.  
  172. Returns:
  173.          0 = success, *pdirp = pointer to malloc-ed directory.
  174.          1 = out of memory;
  175.         -1 = read/seek error or bad header.
  176. */
  177.  
  178. int pak_getdir( FILE *fp, pak_dir **pdirp )
  179. {
  180.     register    int i;
  181.     int         n,k;
  182.     long        hdrloc;
  183.     pak_dir     *pd;
  184.  
  185. /* Read the first header: */
  186.  
  187.     highest_type = 0;                /* Init the highest compression type. */
  188.     version6 = FALSE;                /* Haven't found version 6 stuff yet. */
  189.     hdrloc = ftell(fp);
  190.  
  191.     i = read_pakhdr(fp);                /* Get the first header. */
  192.     if ( i )
  193.     {
  194.         printf("Invalid header seen.\n");
  195.         return -1;
  196.     }
  197.  
  198.     pd = (pak_dir*) malloc( (k=32)*sizeof(pak_dir) );
  199.     if ( pd==NULL )
  200.     {
  201.         printf("Out of memory.\n");
  202.         memory = 1;
  203.         return -1;                        /* out of memory error */
  204.     }
  205.     n = 0;
  206.  
  207.     do                    /* loop once for each new entry found, with */
  208.     {                    /* n=#headers found, k=directory size */
  209.  
  210.         if ( n >= k )                    /* test for current table full */
  211.         {
  212.             /* add 10 more entries to directory: */
  213.             pd = (pak_dir*) realloc( (char*)pd, (k+=16)*sizeof(pak_dir) );
  214.             if ( pd==NULL )
  215.             {
  216.                 printf("Out of memory.\n");
  217.                 memory = 1;
  218.                 return -1;                /* out of memory error */
  219.             }
  220.         }
  221.  
  222.         if (fhdr.type < 20)
  223.         {
  224.             if (fhdr.type > (char)highest_type)
  225.                 highest_type = fhdr.type;
  226.         }
  227.         else
  228.             version6 = TRUE;
  229.         pd[n].type    = fhdr.type;        /* Copy header type. */
  230.         pd[n].floc    = hdrloc;            /* store header location */
  231.         pd[n].slen    = fhdr.slen;        /* copy stored length */
  232. /*         pd[n].olen    = fhdr.olen;         * copy original length */
  233.         pd[n].ddate = fhdr.ddate;        /* copy DOS date */
  234.         pd[n].dtime = fhdr.dtime;        /* copy DOS time */
  235.         strcpy(pd[n].fname,fhdr.fname); /* copy file name */
  236.         ++n;                            /* and increment file count */
  237.  
  238.         hdrloc += fhdr.slen+PAK_HDRLEN+1;
  239.         if (fhdr.type == 1)                /* Type 1 header is shorter! */
  240.             hdrloc -= 4;                /* If type 1, reduce by 4. */
  241.     
  242.         i = fseek( fp, hdrloc, SEEK_SET );
  243.         if ( i )
  244.         {
  245.             printf("Seek error.\n");
  246.             free( (char*)pd );
  247.             return -1;
  248.         }
  249.  
  250.         i = read_pakhdr(fp);
  251.  
  252.     } while ( i==0 );
  253.  
  254.     if ( i<0 )                            /* test for error */
  255.     {
  256.         printf("Invalid header seen.\n");
  257.         free( (char*)pd );
  258.         return -1;
  259.     }
  260.     *pdirp = pd;
  261.     return n;
  262.  
  263. } /* pak_getdir */
  264.  
  265.  
  266. /*
  267.         dir_cmp:        Directory entry compare function for sort.
  268.  
  269. Input:
  270.         lp:     pointer to "left" entry
  271.         rp:     pointer to "right" entry
  272. Return:
  273.         0 if entries are equal
  274.         positive if left "greater than" right
  275.         negative if left "less than" right
  276. */
  277.  
  278. int dir_cmp(pak_dir *lp, pak_dir *rp)
  279. {
  280.     register int j;
  281.  
  282.                                 /* compare unsigned date: */
  283.     j = (lp->ddate > rp->ddate) - (lp->ddate < rp->ddate);
  284.     if (!j)
  285.                                 /* compare unsigned time: */
  286.         j = (lp->dtime > rp->dtime) - (lp->dtime < rp->dtime);
  287.     if (!j)
  288.                                 /* compare full fileid */
  289.         j = strcmp( lp->fname, rp->fname );
  290.     return j;
  291.  
  292. } /* dir_cmp */
  293.  
  294.  
  295. /*
  296.         pak_sort:        Sort one .ARC file.
  297.  
  298. A simple (slow, but small and sure) routine is used here to
  299. sort the directory without the overhead of qsort and recursion.
  300.  
  301. If this sort is replaced with an unstable sort (like quicksort) then
  302. the dir_cmp function should be changed to return compare of original
  303. file location if all fields compare equal. This will preserve
  304. sort stability ... i.e. input order is preserved on equal entries.
  305.  
  306. Return value is 0 if all files were originally in order,
  307.  or 1 if output order is different from input order.
  308.  
  309. */
  310.  
  311. int pak_sort( pak_dir *pdir, int n)
  312. {
  313.     register    int i,j;
  314.     int         i0,j0,k,r;
  315.     pak_dir     tdir;
  316.  
  317.     r = 0;
  318.     for ( j0=1; j0<n; ++j0 )
  319.     {
  320.         i = i0 = j0-1;                    /* starting entry # to compare */
  321.         for ( j=j0; j<n; ++j )
  322.         {
  323.             k = dir_cmp( pdir+i, pdir+j);
  324.             if ( k>0 )
  325.             {                            /* out of order */
  326.                 i = j;                    /* will swap at end */
  327.             }
  328.         }
  329.         if ( i != i0 )                    /* if out of order */
  330.         {
  331.             tdir = pdir[i];             /* swap smallest entry */
  332.             pdir[i] = pdir[i0];         /* (at most n-1 times) */
  333.             pdir[i0] = tdir;
  334.             r = 1;                        /* tell caller that input was */
  335.                                         /* not in order */
  336.         }
  337.     }
  338.     return r;
  339.  
  340. } /* pak_sort */
  341.  
  342.  
  343. /*
  344.         pak_write:        Copy packed source files to dest in sorted order.
  345. */
  346.  
  347. int pak_write( FILE *src, FILE *dst, pak_dir* dirp, int n )
  348.  
  349. /*     FILE        *src;             * opened source file */
  350. /*     FILE        *dst;             * opened dest file */
  351. /*     pak_dir     *dirp;             * sorted directory of source */
  352. /*     int         n;                 * number of entries in source directory */
  353. {
  354.     register int i,j;
  355.     int         k;
  356.     int         buf_size;
  357.     long        len,start,end;
  358.  
  359.     buf_size = MAX_BUFSIZE;
  360.     do
  361.     {
  362.         pak_buf = malloc(buf_size);
  363.         if (pak_buf == NULL)
  364.             buf_size >>= 1;
  365.     } while (pak_buf == NULL && buf_size > 0);
  366.     if (pak_buf == NULL)
  367.     {
  368.         printf("Out of memory.\n");
  369.         memory = 1;
  370.         return -1;
  371.     }
  372.  
  373.     for ( i=0; i<n; ++i )
  374.     {                            /* once for each member file */
  375.  
  376.         len = dirp[i].slen + 1 + 
  377.                     ((1 == dirp[i].type) ? (PAK_HDRLEN - 4) : PAK_HDRLEN);
  378.  
  379.         if (!quiet)
  380.         {
  381.             printf("  Copying: %-13s - loc=%-6ld  len=%-6ld\n",
  382.                     dirp[i].fname,
  383.                     dirp[i].floc,
  384.                     len);
  385.         }
  386.  
  387.         /* point to start of member, test for error: */
  388.         j = fseek(src, dirp[i].floc, SEEK_SET);
  389.         if ( j )
  390.         {
  391.             printf("Seek error.\n");
  392.             free(pak_buf);
  393.             return -1;
  394.         }
  395.  
  396.         /* copy member to destination: */
  397.         for ( end=0; end<len; )
  398.         {
  399.             start = end;
  400.             end = start+(k=buf_size);
  401.             if (end>len)
  402.                 k = (int)((end=len)-start);
  403.             j = fread( pak_buf, 1, k, src );
  404.             if ( j != k )
  405.             {
  406.                 printf("Read error.\n");
  407.                 free(pak_buf);
  408.                 return -1;
  409.             }
  410.             j = fwrite( pak_buf, 1, k, dst );
  411.             if ( j != k )
  412.             {
  413.                 printf("Write error.\n");
  414.                 free(pak_buf);
  415.                 return -1;
  416.             }
  417.         }
  418.     }
  419.  
  420.     free(pak_buf);
  421.     /* Add EOF mark to (end of) destination: */
  422.     fputc( PAK_MARK, dst );
  423.     fputc( '\0', dst );
  424.     if ( ferror(dst) )
  425.     {
  426.         printf("Write error.\n");
  427.         return -1;
  428.     }
  429.  
  430.     return 0;
  431.  
  432. } /* pak_write */
  433.  
  434.  
  435.  
  436. /*
  437.         pak_dosort:     Read/sort/rewrite one .ARC file.
  438.  
  439. Returns 0 if successful, or error:
  440.    1 = Can't open/read source. (missing pakfile or DOS error)
  441.    2 = Can't create/write dest. (maybe disk or directory full)
  442.    3 = Can't delete old source file. (read-only)
  443.    4 = Can't rename temp file to source name. (DOS error)
  444.    5 = Out of memory.
  445.    6 = Invalid pakfile. (Header error)
  446. */
  447.  
  448. int pak_dosort(char *fpath, char *fn, int sort)
  449. {
  450.     register int i,j;
  451.     int         n;
  452.     pak_dir     *pdir;            /* pointer to (malloced) directory */
  453.                                 /*    built by pak_getdir */
  454.     FILE        *src;            /* source file */
  455.     FILE        *dst;            /* source file */
  456.     char        *fnptr;         /* location of filename in fname */
  457.  
  458. #ifdef AMIGA
  459.     char        srcname[108];
  460.     char        fname[108];
  461. #else
  462.     char        srcname[64];    /* save source filename */
  463.     char        fname[64];
  464. #endif
  465.     memory = 0;
  466.     strcpy(fname,fpath);
  467.     fnptr = fname + strlen(fname);
  468.     strcpy(fnptr,fn);                    /* make full path to file */
  469.     if (!quiet)
  470.         printf("Searching:  %s\n",fname); /* and identify */
  471.     src = fopen( fname, "rb" );         /* and open file */
  472.     if ( src==NULL )
  473.     {
  474.         printf("Can't open %s.\n", fname);
  475.         return 1;
  476.     }
  477. #ifdef AMIGA
  478.     fseek (src, 0L, SEEK_END);
  479.     paklen = ftell(src);
  480.     fseek (src, 0L, SEEK_SET);
  481. #else
  482.     paklen = filelength(fileno(src));    /* get file length in global */
  483. #endif
  484.     pdir = NULL;                        /* clear directory pointer */
  485.     n = pak_getdir( src, &pdir );        /* get directory */
  486.     if (memory)
  487.         return 5;
  488.     if ( n<1 )
  489.     {
  490.         printf("Invalid file format, not changed.\n");
  491.         fclose(src);
  492.         return 6;
  493.     }
  494.     if (version6 || !sort)                /* Don't sort if version 6 format. */
  495.     {
  496.         free( (char*)pdir );
  497.         fclose(src);                    /* unconditionally close source */
  498.         return 0;
  499.     }
  500.  
  501.     i = pak_sort( pdir, n);
  502.     if ( i==0 )
  503.     {
  504.         printf("Already in order, not changed.\n");
  505.         free( (char*)pdir );
  506.         fclose(src);                        /* unconditionally close source */
  507.         return 0;
  508.     }
  509.  
  510. /* pakfile is not in order, create sorted copy & rename: */
  511.  
  512.     strcpy( srcname, fname );
  513.     strcpy( fnptr, "PAKSRTMP.$$$" );
  514.     dst = fopen( fname, "wb" );
  515.     if ( dst==NULL )
  516.     {
  517.         printf("Can't create: %s\n", fname );
  518.         free( (char*)pdir );
  519.         return 1;
  520.     }
  521.  
  522.     j = pak_write( src, dst, pdir, n ); /* copy source to dest tempfile */
  523.     fclose(src);                        /* unconditionally close source */
  524.     free( (char*)pdir );                /*    and release directory mem */
  525.     i = fclose(dst);                    /* close dest file */
  526.  
  527.     if ( j || i )                        /* if error on write or close */
  528.     {
  529.             if ( !j )                    /* identify close error */
  530.                 printf("Can't close: %s\n",fname);
  531.             unlink(fname);
  532.             return 2;
  533.     }
  534.  
  535.     j = unlink(srcname);                /* delete source */
  536.     if ( j )
  537.     {                                    /* can't delete, read-only? */
  538.         printf( "Can't delete original.\n");
  539.         unlink(fname);                    /* delete sorted temp copy */
  540.         return 3;                        /* return error */
  541.     }
  542.     j = rename( fname, srcname );
  543.     if ( j )
  544.     {
  545.         printf("Rename error: %d, original unsorted data lost!\n");
  546.         printf("Sorted data retained in temp output file for recovery:\n");
  547.         printf("%s\n",fname);
  548.         return 4;
  549.     }
  550.  
  551.     return 0;
  552.  
  553. } /* pak_dosort */
  554.